#include "multitasker.h" 
#include "int80.h"
#include "paging.h"
#include "malloc.h"

#define INIFL 0x200

#define INIT 0

#define SIGKILL 9

/*
Estructuras que ayudan a manejar el stack. 
param_t representa como estan los parametros en el stack antes de ejecutar el main.
initial_stack_t representa como esta el stack cuando se cra un nuevo proceso.
*/
typedef struct{
	int argc;
	char** argv;
} __attribute__((packed)) param_t;

typedef struct{
	registers_t regs;
	uint32_t retaddr;
	param_t param;
} __attribute__((packed)) initial_stack_t;


void set_cr3(unsigned int page_dir);
unsigned int get_cr3();
void enable_paging();

/*
Funciones para obtener el valor de algunos registros.
*/
uint32_t get_stack();
void set_stack(uint32_t esp);
uint32_t get_cs();
uint32_t get_ds();

/*
Funcion de usuario que se llama desde el kernel para guardar el contexto y ceder el procesador.
*/
void yeld();

/*
Vector y su offset que sirven para aproximar que porcentaje del procesador esta usando cada proceso.
*/
int percentage[100];
int percentage_pos;


/*
Funciones que dependen de la implementacion del algoritmo de scheduling,
 y que por esa rason estan definidas en otro archivo.
*/
int next_task();
void block(int state);
void unblock(int task);
void init_scheduler();



tty_t* tty=NULL;
/*
Flag que indica si el multitasker ya fue inicializado.
*/
int init=0;

/*
Proximo pid.
*/
int pid_count=0;


/*
Vector de tareas.
*/
task_t task_vector[MAX_TASK];


/*
Tarea que esta siendo ejecutada.
*/
int actual_task=INIT;


//REVISAR ESTO!!!!
task_t  getActualTask(void){

	task_vector[actual_task];
}

/*
para el cambio de stack
*/
char stack_repuesto[2048];
unsigned int my_cr;
unsigned int my_esp;
char** params;
param_t param;
initial_stack_t* s;
int pagedir;
unsigned int retaddr;
unsigned int eip;
int k;


param_t param_rep;
char param_container[1024];
int param_pointer;

/*
Funcion para cambiar la tty.
*/
tty_t* get_tty(){


	tty=&task_vector[actual_task].tty;
	
	return tty;
}



/*
retorno: 1 si la tarea que esta corriendo fue señalizada
0 en otro caso.
*/
int signaled(){
	if(task_vector[actual_task].signal_recived){
		return 1;
	}
	return 0;
}

int get_fd(int i){
	return task_vector[actual_task].fds[i];
}

int set_fd(int n){
	
	int i;
	for(i=0;i<256 && task_vector[actual_task].fds[i]!=-1;i++);
	
	if(i>=256){
		return -1;
	}
	
	task_vector[actual_task].fds[i]=n;
	
	return i;
}

void set_fd2(int i,int n){
	task_vector[actual_task].fds[i]=n;
}

/*
Agrega la tarea que esta corriendo a una cola de bloqueados indicada por 'first'.
*/
void add_actual_task_to_block_list(int* first){
	task_vector[actual_task].blocked_list=first;
	task_vector[actual_task].next_blocked=*first;
	*first = actual_task;
}

/*
Quita la tarea 'task' de la cola 'first'.
*/
void delete_task_from_block_list(int* first, int task){
	while(*first!=-1){
		if(*first==task){
			unblock(*first);
			*first = task_vector[*first].next_blocked;
			 task_vector[*first].blocked_list=NULL;
			return;
		}
		else{
			first = &task_vector[*first].next_blocked;
		}
	}
}

/*
Desbloquea todos los procesos bloqueados en la lista indicada por 'first'.
*/
void unblock_all_from_when(int* first, state_t state){
	while(*first!=-1){
		unblock(*first);
		*first = task_vector[*first].next_blocked;
		 task_vector[*first].blocked_list=NULL;
	}
}

/*
Retorna la primera posicion del vector de tareas en estar vacia.
*/
int not_present(){
	int i;
	for(i=0;i<MAX_TASK;i++){
		if(!task_vector[i].present){
			return i;
		}
	}
	return -1;
}


/*
Retorna la posicion del vector de tareas, cuya tarea tiene el pid 'pid'.
*/
int get_task_by_pid(int pid){
	int i;
	for(i=0;i<MAX_TASK;i++){
		if(task_vector[i].present && task_vector[i].pid==pid){
			return i;
		}
	}
	return -1;
}

void freeProcMem(int proc){
	
	my_esp=get_stack();
	set_stack((uint32_t)stack_repuesto+1024-8);
	my_cr=get_cr3();
	set_cr3(task_vector[proc].entorno.cr3);
	
	free_heap();
	
	set_cr3(my_cr);
	set_stack(my_esp);
	
	set_stack((uint32_t)stack_repuesto+1024-8);
	set_cr3(task_vector[proc].entorno.cr3);
	
	free_stack();
	
	set_cr3(my_cr);
	set_stack(my_esp);
}


/*
Manejador del systemcall sleep, que bloquea la tarea hasta que alguien la despierte.
*/
uint32_t sys_sleep(registers_t* regs){
	block(Blocked_sleep);
	yeld();
	return 0;
}

uint32_t sys_sleep2(registers_t* regs){
	block(Blocked_sleep);
	return 0;
}
/*
Manejador del systemcall wakeup, que desbloquea la tarea que se durmio con el systemcall sleep.
*/
uint32_t sys_wakeup(registers_t* regs){
	int task=get_task_by_pid(regs->ebx);
	if(task!=-1 && task_vector[task].present && task_vector[task].state==Blocked_sleep){
		unblock(task);
	}
	return 0;
}

/*
Funcion que elige a que tarea a cederle el procesador a continuacion.
retorna: 0 si se quere mantener el stack que se estaba usando,
o la posicion del stack, si se quiere cambiar por otro.
*/
uint32_t scheduler(registers_t* regs){

	if(!init ){
		return 0;
	}
	/*
	Si estoy inicializado y vengo del timer tick, la tarea actual tiene un tick menos por correr,
	y uso un tick mas de los ultimos 100.
	*/
	if (regs->eax==1){
		task_vector[actual_task].ticks_to_run--;
		percentage[percentage_pos]=task_vector[actual_task].pid;
		percentage_pos=percentage_pos==99?0:percentage_pos+1;
	}
	
	if(task_vector[actual_task].pid!=0){
		grow_stack();
	}
	
	/*
	Si la tarea actual no se bloqueo y le quedan ticks por correr,
	no tengo nada mas que hacer, y la tarea actual va a seguir corriendo
	*/

	if(task_vector[actual_task].state==Running && task_vector[actual_task].ticks_to_run > 0){
		return 0;	
	}

	
	/*
	Si la tarea actual se bloqueo antes de que se le termine el tiempo,
	le subo la prioridad
	*/
	if(task_vector[actual_task].state != Running){
		if(task_vector[actual_task].priority!=MAX_PRIORITY && task_vector[actual_task].priority!=MIN_PRIORITY){
			task_vector[actual_task].priority++;
		}
	}
	/*
	Si a la tarea actual se le termine el tiempo antes de bloquearse ,
	le bajo la prioridad
	*/
	if(task_vector[actual_task].ticks_to_run == 0){
		if(task_vector[actual_task].priority!=MIN_PRIORITY && task_vector[actual_task].priority!=MIN_PRIORITY+1){
			task_vector[actual_task].priority--;
		}
	}
	
	/*
	Me guardo la posicion del stack, para poder recuperar el contexto,
	en el bloque de control del proceso.
	*/
	task_vector[actual_task].entorno.esp=regs->real_esp;
	
	/*
	Si no se bloqueo, cambio el estado a listo.
	*/
	if(task_vector[actual_task].state==Running)
		task_vector[actual_task].state=Ready;
	
	/*
	Cambio la tarea actual por la proxima.
	*/
	actual_task=next_task();
	
	/*
	Seteo la cantidad de ticks que va a correr el proceso antes de que le saquen el procesador,
	basado en su prioridad (como pedia la consigna).
	*/
	task_vector[actual_task].ticks_to_run=4*task_vector[actual_task].priority+1;
	
	/*
	Seteo el estado de la nueva tarea a correr en corriendo.
	*/
	if(task_vector[actual_task].state==Ready)
		task_vector[actual_task].state=Running;
	
	/*
	Preparo el stack de la nueva tarea para devolverlo.
	*/
	uint32_t entorno=(uint32_t)&task_vector[actual_task].entorno;
	set_tss_cr3(task_vector[actual_task].entorno.cr3);

	/*
	Llamo a la tty.
	*/
	tty_func(tty);
	
	/*
	Corro el manejador de señal si es que el proceso a ejecutar fue señalizado.
	*/
	if(task_vector[actual_task].signal_recived){
		int signal=task_vector[actual_task].signal_recived;
		task_vector[actual_task].signal_recived=0;
		_Sti();
		task_vector[actual_task].signals[signal](signal);
		_Cli();
	}
	/*
	Retorno el valor del nuevo stack.
	*/
	return entorno;
}


/*
Manejador del systemcall exit, que bloquea el proceso, y se queda esperando que
el padre haga un wait pid sobre su pid para liberar el bloque de control del 
proceso.
*/
uint32_t sys_exit(registers_t* regs){

	/*
	Guarda el valor de retorno del proceso.
	*/
	task_vector[actual_task].exit_status=regs->ebx;
	
	int i;
	for(i=0;i<256;i++){
		if(task_vector[actual_task].fds[i]!=-1){
			regs->ebx=task_vector[actual_task].fds[i];
			sys_close(regs);
		}
	}
	
	
	/*
	Le paso todos los hijos zombies a init.
	*/
	if(task_vector[actual_task].zombies!=-1){
		int task=task_vector[actual_task].zombies;
		while(task_vector[task].next_zombie!=-1){
			task=task_vector[task].next_zombie;
		}
		
		task_vector[task].next_zombie=task_vector[INIT].zombies;
		task_vector[INIT].zombies=task_vector[actual_task].zombies;
	}
	
	/*
	Busca al padre.
	*/
	int parent=get_task_by_pid(task_vector[actual_task].ppid);
	
	/*
	Si no tiene padre, se lo mando a init.
	*/
	if(parent==-1){
		parent=INIT;
	}
	
	/*
	Se agraga a la cola de zombies del padre.
	*/
	task_vector[actual_task].next_zombie=task_vector[parent].zombies;
	task_vector[parent].zombies=actual_task;
	
	/*
	Si el padre lo esta haciendo un wait pid, lo desbloquea.
	*/
	if(task_vector[parent].state==Blocked_wait){
		unblock(parent);
	}
	
	/*
	Se bloquea y cede el procesador.
	*/
	block(Zombie);
	return scheduler(regs);
}


/*
Manejador del systemcall wait. Bloque el proceso hasta que un hijo se muera, y cuando pasa, libera 
el bloque de control del proceso y retorna su valor de retorno.
*/
uint32_t sys_wait(registers_t* regs){
	/*
	Si no hay hijos muertos me bloqueo y cedo el procesador guardando el contexto.
	*/
	if(task_vector[actual_task].zombies==-1){
		block(Blocked_wait);
		yeld();
	
		/*
		Si me desbloquie por una señal retorno -1 del lado del usuario.
		*/
		if(task_vector[actual_task].zombies==-1){
			regs->eax=-1;
			/*
			Retorno cero porque no quiero cambiar el stack.
			*/
			return 0;
		}
	}
	
	
	freeProcMem(task_vector[actual_task].zombies);
 	
	 /*
	Libero el bloque de control del proceso.
	*/
	task_vector[task_vector[actual_task].zombies].present=0;
	
	/*
	Guardo el valor de retorno en el lugar apuntado por ebx.
	*/
	*((int*)regs->ebx)=task_vector[task_vector[actual_task].zombies].exit_status;

	/*
	Elimino al hijo de la cola.
	*/
	task_vector[actual_task].zombies=task_vector[task_vector[actual_task].zombies].next_zombie;
	
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}


/*
Manejador del systemcall waitpid. Bloque el proceso hasta que un hijo con cierto pid se muera,
y cuando pasa, libera el bloque de control del proceso y retorna su valor de retorno.
*/
uint32_t sys_waitpid(registers_t* regs){

	/*
	Si el pid que me pasaron es igual a -1, hago un wait en vez de un waitpid.
	*/
	if(regs->ecx==-1){
		return sys_wait(regs);
	}
	
	
	int i;
	int child=-1;
	
	do{
		/*
		Si algun hijo con el pid que me pasaron esta en la cola de zombies del proceso actual,
		es el hijo que estaba esperando.
		*/
		for(i=task_vector[actual_task].zombies ; i!=-1 && child==-1 ; i=task_vector[i].next_zombie){
			if(task_vector[i].pid==regs->ecx){
				child=i;
			}
		}
	
		/*
		En otro caso me bloqueo esperandolo.
		*/
		if(child==-1){
			block(Blocked_wait);
			yeld();
		}
	}while(child==-1);
	
	
	freeProcMem(child);
	
	/*
	Libero el bloque de control del proceso.
	*/
	task_vector[child].present=0;
	
	/*
	Guardo el valor de retorno en el lugar apuntado por ebx.
	*/
	*((int*)regs->ebx)=task_vector[child].exit_status;
		
	
	/*
	Elimino al hijo de la cola.
	*/	
	if(task_vector[actual_task].zombies==child){
		task_vector[actual_task].zombies=task_vector[child].next_zombie;
	}
	else{
		for(i=task_vector[actual_task].zombies ; i!=-1 && child==-1 ; i=task_vector[i].next_zombie){
			if(task_vector[i].next_zombie==child){
				task_vector[i].next_zombie = task_vector[child].next_zombie;
			}
		}
	}
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}

/*
Manejador del systemcall signal. Coloca un manejador de señales, que a diferencia del de unix,
no se va una vez que se ejecuto, sino que queda ahi hasta que se lo vuelva a cambiar.
*/
uint32_t sys_signal(registers_t* regs){
	if((regs->ebx<=0 || regs->ebx>=MAX_SIGNAL) && regs->ebx!= SIGKILL){
		return 0;
	}
	task_vector[actual_task].signals[regs->ebx]=(sighandler_t)regs->ecx;
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}

/*
Manejador de systemcall kill. Proboca la ejecucion del manejador de señales correspondiente a la señal enviada.
*/
uint32_t sys_kill(registers_t* regs){
	if(regs->ecx<=0 || regs->ecx>=MAX_SIGNAL){
		return 0;
	}
	
	/*
	Busca la tarea a señalizar.
	*/
	int task_signaled=get_task_by_pid(regs->ebx);
	
	
	if(task_signaled==-1){
		return 0;
	}
	
	
	/*
	Desbloquea la tarea si es que estaba bloqueada y la quita de la lista de espera.
	*/
	if(task_vector[task_signaled].state==Blocked_wait || task_vector[task_signaled].state==Blocked_sleep){
		unblock(task_signaled);
	}
	
	
	if(task_vector[task_signaled].state==Blocked_write || task_vector[task_signaled].state==Blocked_read){
		delete_task_from_block_list(task_vector[task_signaled].blocked_list, task_signaled);
	}
	
	
	/*
	Marca la tarea como señalizada por la señal correspondiente.
	*/
	task_vector[task_signaled].signal_recived=regs->ecx;
		
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}

/*
Un default para los manejadores de señales no muy feliz, pero suficiente.
*/
void signal_default(int signal){
	exit(128+signal);
}


/*
Manejador del systemcall fork. Crea un proceso y lo pone listo para ejecutarse.
A diferencia del de unix, hace un exec ademas de un fork, y los parametros no 
son una lista terminada en null, sino una estructura definida arriva.
*/
uint32_t sys_fork(registers_t* regs){
	
	retaddr=regs->ecx;
	eip=regs->ebx;
	params = (char**)regs->edx;
	
	param.argc = 0;
	
	
	int i;	
	for(i=0;params[i]!=NULL;i++){
		param.argc++;
	}
	
	param_pointer=0;
	
	param_rep.argv=(char**)&param_container[param_pointer];
	param_pointer+=(unsigned)(param.argc+1)*sizeof(char*);
	for(i=0;i<param.argc;i++){
		param_rep.argv[i]= &param_container[param_pointer];
		param_pointer+=(unsigned)strlen(params[i])+1;
		strcpy(param_rep.argv[i], params[i]);
	}
	
	
	/*
	Obtengo un bloque de control de proceso vacio, y lo marco como no vacio.
	*/
	int new_task=not_present();
	task_vector[new_task].present=1;
	
	/*
	Seteo en vacio la lista de bloqueado, en no recivida las señales,
	en vacia la lista de zombies, y los siguientes.
	*/
	task_vector[new_task].blocked_list=NULL;
	
	task_vector[new_task].signal_recived=0;
	
	task_vector[new_task].zombies=-1;
	task_vector[new_task].next_zombie=-1;
	
	task_vector[new_task].next_blocked=-1;
	
	/*
	Seteo el ppid con el pid del padre(osea la tarea actual).
	*/
	task_vector[new_task].ppid=task_vector[actual_task].pid;
	

	my_esp=get_stack();
	set_stack((uint32_t)stack_repuesto+1024-8);


	
	pagedir=new_page_dir();

	
	
	//initial_stack_t* s=(initial_stack_t*)(task_vector[new_task].stack+STACK_SIZE)-1;

	
	
	my_cr=get_cr3();
	set_cr3(pagedir*4096);
		/*
	Preparo el stack inicial.
	*/
	new_heap();
	
	init_heap2();
	
	if(param.argc>0){
		param.argv = malloc((unsigned)(param.argc+1)*sizeof(char*));
		param.argv[param.argc]=NULL;
		for(k=0;k<param.argc;k++){
			param.argv[k]=malloc((unsigned)strlen(param_rep.argv[k])+1);
			strcpy(param.argv[k], param_rep.argv[k]);
		}
	}
	
	set_cr3(my_cr);
	set_stack(my_esp);
	
	
	set_stack((uint32_t)stack_repuesto+1024-8);
	set_cr3(pagedir*4096);
	
	new_stack();
	
	s=((initial_stack_t*)4294967291u)-1;
	
	
	s->param=param;
	
	s->retaddr=retaddr;
	s->regs.eflags=INIFL;
	s->regs.cs=(unsigned)get_cs();
	s->regs.eip=eip;
	s->regs.ds=(unsigned)get_ds();
	
	s->regs.esp=(unsigned)s;


	
	set_cr3(my_cr);
	set_stack(my_esp);
	
	
	

	/*
	Guardo la posicion del stack pointer en el bloque de control del proceso.
	*/
	task_vector[new_task].entorno.esp=(unsigned)((int*)s+1);
	task_vector[new_task].entorno.cr3=pagedir*4096;
	
	/*
	Le asigno un pid el proceso.
	*/
	task_vector[new_task].pid=pid_count;
	
	/*
	Le asigno la prioridad default.
	*/
	task_vector[new_task].priority=DEFOULT_PRIORITY;
	
	task_vector[new_task].name[0]='\0';
	/*
	Lo agrego a la estructura del scheduler.
	*/
	unblock(new_task);
	
	/*
	Le seteo el manejador de sñales default para todas las señales.
	*/
	for(i=0;i<MAX_SIGNAL;i++){
		task_vector[new_task].signals[i]=signal_default;
	}
	
	/*
	Copio los file descriptrs del padre.
	*/
	for(i=0;i<256;i++){
		task_vector[new_task].fds[i]=task_vector[actual_task].fds[i];
		if(task_vector[actual_task].fds[i]!=-1){
			increment_count(task_vector[actual_task].fds[i]);
		}
	}
	task_vector[new_task].tty=task_vector[actual_task].tty;
	
	
	/*
	Retorno el pid del lado del usuario.
	*/
	regs->eax=pid_count++;
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}


unsigned int heap_end;
unsigned int stack_start;
uint32_t sys_stacklimit(registers_t* regs){

	int proc = get_task_by_pid(regs->ebx);
	
	if(proc==-1){
		regs->eax=0;
		return 0;
	}
	
	my_esp=get_stack();
	set_stack((uint32_t)stack_repuesto+1024-8);
	my_cr=get_cr3();
	set_cr3(task_vector[proc].entorno.cr3);
	
	stack_start=stack_limit();
	
	set_cr3(my_cr);
	set_stack(my_esp);
	
	regs->eax=stack_start;

	
	return 0;

}

uint32_t sys_heaplimit(registers_t* regs){

	int proc = get_task_by_pid(regs->ebx);
	
	if(proc==-1){
		regs->eax=0;
		return 0;
	}
	
	my_esp=get_stack();
	set_stack((uint32_t)stack_repuesto+1024-8);
	my_cr=get_cr3();
	set_cr3(task_vector[proc].entorno.cr3);
	
	heap_end=heap_limit();
	
	set_cr3(my_cr);
	set_stack(my_esp);
	
	regs->eax=heap_end;
	
	return 0;

}

uint32_t sys_top(registers_t* regs){
	top_t* top=(top_t*)regs->ebx;
	
	top->running=0;
	top->blocked=0;
	top->ready=0;
	top->zombies=0;
	top->cant=0;
	
	int i;
	char* state_name;
	
	for(i=0;i<MAX_TASK;i++){
		if(task_vector[i].present){
			switch(task_vector[i].state){
				case Running:
					top->running++;
					state_name="running ";
					break;
				case Ready:
					top->ready++;
					state_name="running ";
					break;
				case Zombie:
					top->zombies++;
					state_name="zombie  ";
					break;
				case Blocked_wait:
				case Blocked_write:
				case Blocked_read:
				case Blocked_sleep:
					top->blocked++;
					state_name="sleeping";
					break;
				default:
					state_name="unknow  ";
					
			}
			
			int j;
			int cant=0;
			for(j=0;j<100;j++){
				if(percentage[j]==task_vector[i].pid){
					cant++;
				}
			}
			
			top->cant++;
			top->processes[top->cant-1].pid=task_vector[i].pid;
			top->processes[top->cant-1].porcentage=cant;
			top->processes[top->cant-1].state=state_name;
			strcpy(top->processes[top->cant-1].name,task_vector[i].name);
			
			
		}
	
	}
	return 0;
}

/*
Manejador del systemcall getpid. Retorna el pid del lado del usuario
*/
uint32_t sys_getpid(registers_t* regs){
	regs->eax=task_vector[actual_task].pid;
	
	/*
	Retorno cero porque no quiero cambiar el stack.
	*/
	return 0;
}

/*
Manejador del systemcall yeld. Cede el procesador.
*/
uint32_t sys_yeld(registers_t* regs){
	return scheduler(regs);
}


uint32_t sys_setpriority(registers_t* regs){
	if(regs->ebx>=MIN_PRIORITY && regs->ebx<=MAX_PRIORITY){
		task_vector[actual_task].priority=regs->ebx;
	}
	return 0;
}


uint32_t sys_usemytty(registers_t* regs){

	tty=&task_vector[actual_task].tty;
	
	return 0;
}



uint32_t sys_killzombies(registers_t* regs){
	/*
	Le paso todos los hijos zombies a init.
	*/
	if(task_vector[INIT].zombies!=-1){
		int task=task_vector[INIT].zombies;
		while(task_vector[task].next_zombie!=-1){
			task=task_vector[task].next_zombie;
		}
	
		task_vector[task].next_zombie=task_vector[actual_task].zombies;
	}
	else{
		task_vector[INIT].zombies=task_vector[actual_task].zombies;
	}
	
	task_vector[actual_task].zombies=-1;
	
	if(task_vector[INIT].state==Blocked_wait){
		unblock(INIT);
	}
	
	return 0;
}

uint32_t sys_setname(registers_t* regs){

	int proc = get_task_by_pid(regs->ecx);
	strcpy(task_vector[proc].name,regs->ebx);
	
	return 0;
}

/*
Funcion que inicia el multitasker.
*/
void init_multitasker(){
	/*
	Seteo los manejadores de systemcalls.
	*/
	register_functionality(0,sys_yeld);
	register_functionality(1,sys_exit);
	register_functionality(2,sys_fork);
	register_functionality(7,sys_waitpid);
	register_functionality(20,sys_getpid);
	register_functionality(32,sys_kill);
	register_functionality(48,sys_signal);
	register_functionality(97,sys_setpriority);
	register_functionality(110,sys_top);
	register_functionality(111,sys_stacklimit);
	register_functionality(112,sys_heaplimit);
	register_functionality(161,sys_sleep2);
	register_functionality(162,sys_sleep);
	register_functionality(163,sys_wakeup);
	register_functionality(200,sys_usemytty);
	register_functionality(203,sys_killzombies);
	register_functionality(204,sys_setname);
	
	/*
	Los bloques de control de proceso estan todos libres, menos el primero.
	*/
	int i;
	for(i=1;i<MAX_TASK;i++){
		task_vector[i].present=0;
	}
	
	/*
	Inicializo el sistema para calcular el uso de la cpu.
	*/
	for(i=0;i<100;i++){
		percentage[i]=1;
	}
	percentage_pos=0;
	
	/*
	Creo el proceso init como el proceso actual.
	*/
	task_vector[actual_task].present=1;
	task_vector[actual_task].state=Running;
	
	task_vector[actual_task].pid=pid_count;
	task_vector[actual_task].ppid=pid_count++;
	task_vector[actual_task].zombies=-1;
	task_vector[actual_task].priority=MIN_PRIORITY;
	
	unsigned int pagedir=new_page_dir();
	task_vector[actual_task].entorno.cr3=4096*pagedir;
	

	
	/*
	Seteo los file descriptors.
	*/
	task_vector[actual_task].fds[0]=0;
	task_vector[actual_task].fds[1]=1;
	for(i=2;i<256;i++){
		task_vector[actual_task].fds[i]=-1;
	}
	
	
	/*
	Inicializacion de cosas particulares de cada algoritmo de scheduling.
	*/
	init_tty();
	init_scheduler();
	
	
	set_cr3(task_vector[actual_task].entorno.cr3);
	
	enable_paging();
	/*
	Seteo el multitasker como ya inicializado.
	*/

	init=1;
}
